<script setup lang="ts">
import { ref, computed, watch } from 'vue'

interface FormField {
  key: string
  label: string
  type: 'text' | 'email' | 'password' | 'number' | 'select' | 'radio' | 'checkbox' | 'textarea' | 'date' | 'switch'
  required?: boolean
  disabled?: boolean
  placeholder?: string
  options?: { label: string; value: any }[]
  rules?: any[]
  cols?: number
  hint?: string
  prepend?: string
  append?: string
  multiple?: boolean
  rows?: number
}

interface Props {
  fields: FormField[]
  modelValue: Record<string, any>
  loading?: boolean
  readonly?: boolean
  validateOnMount?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  loading: false,
  readonly: false,
  validateOnMount: false
})

const emit = defineEmits<{
  'update:modelValue': [value: Record<string, any>]
  'submit': [value: Record<string, any>]
  'change': [key: string, value: any]
}>()

const formRef = ref()
const formData = ref({ ...props.modelValue })
const isValid = ref(false)

// 计算表单值
const computedValue = computed({
  get: () => formData.value,
  set: (value) => {
    formData.value = value
    emit('update:modelValue', value)
  }
})

// 更新字段值
const updateField = (key: string, value: any) => {
  computedValue.value = {
    ...computedValue.value,
    [key]: value
  }
  emit('change', key, value)
}

// 获取字段规则
const getFieldRules = (field: FormField) => {
  const rules = [...(field.rules || [])]
  
  if (field.required) {
    rules.unshift((v: any) => !!v || `${field.label}是必填项`)
  }
  
  return rules
}

// 提交表单
const handleSubmit = async () => {
  const { valid } = await formRef.value?.validate()
  if (valid) {
    emit('submit', computedValue.value)
  }
}

// 重置表单
const resetForm = () => {
  formRef.value?.reset()
  formData.value = { ...props.modelValue }
}

// 验证表单
const validateForm = () => {
  return formRef.value?.validate()
}

// 监听外部数据变化
watch(() => props.modelValue, (newVal) => {
  formData.value = { ...newVal }
}, { deep: true })

// 暴露方法
defineExpose({
  validate: validateForm,
  reset: resetForm,
  submit: handleSubmit
})
</script>

<template>
  <VForm
    ref="formRef"
    v-model="isValid"
    :readonly="readonly"
    @submit.prevent="handleSubmit"
  >
    <VRow>
      <VCol
        v-for="field in fields"
        :key="field.key"
        :cols="field.cols || 12"
        :md="field.cols || 6"
      >
        <!-- 文本输入框 -->
        <VTextField
          v-if="['text', 'email', 'password', 'number'].includes(field.type)"
          :model-value="computedValue[field.key]"
          @update:model-value="updateField(field.key, $event)"
          :label="field.label"
          :type="field.type"
          :placeholder="field.placeholder"
          :disabled="loading || field.disabled"
          :required="field.required"
          :rules="getFieldRules(field)"
          :prepend-icon="field.prepend"
          :append-icon="field.append"
          :hint="field.hint"
          variant="outlined"
        />

        <!-- 选择框 -->
        <VSelect
          v-else-if="field.type === 'select'"
          :model-value="computedValue[field.key]"
          @update:model-value="updateField(field.key, $event)"
          :label="field.label"
          :items="field.options"
          :placeholder="field.placeholder"
          :disabled="loading || field.disabled"
          :required="field.required"
          :rules="getFieldRules(field)"
          :multiple="field.multiple"
          :hint="field.hint"
          variant="outlined"
          item-title="label"
          item-value="value"
        />

        <!-- 单选框组 -->
        <VRadioGroup
          v-else-if="field.type === 'radio'"
          :model-value="computedValue[field.key]"
          @update:model-value="updateField(field.key, $event)"
          :disabled="loading || field.disabled"
          :rules="getFieldRules(field)"
        >
          <template #label>
            <span class="field-label">{{ field.label }}</span>
            <span v-if="field.required" class="text-red">*</span>
          </template>
          <VRadio
            v-for="option in field.options"
            :key="option.value"
            :label="option.label"
            :value="option.value"
          />
        </VRadioGroup>

        <!-- 多选框 -->
        <VCheckbox
          v-else-if="field.type === 'checkbox'"
          :model-value="computedValue[field.key]"
          @update:model-value="updateField(field.key, $event)"
          :label="field.label"
          :disabled="loading || field.disabled"
          :rules="getFieldRules(field)"
          :hint="field.hint"
        />

        <!-- 文本域 -->
        <VTextarea
          v-else-if="field.type === 'textarea'"
          :model-value="computedValue[field.key]"
          @update:model-value="updateField(field.key, $event)"
          :label="field.label"
          :placeholder="field.placeholder"
          :disabled="loading || field.disabled"
          :required="field.required"
          :rules="getFieldRules(field)"
          :rows="field.rows || 3"
          :hint="field.hint"
          variant="outlined"
        />

        <!-- 日期选择器 -->
        <VTextField
          v-else-if="field.type === 'date'"
          :model-value="computedValue[field.key]"
          @update:model-value="updateField(field.key, $event)"
          :label="field.label"
          type="date"
          :disabled="loading || field.disabled"
          :required="field.required"
          :rules="getFieldRules(field)"
          :hint="field.hint"
          variant="outlined"
        />

        <!-- 开关 -->
        <VSwitch
          v-else-if="field.type === 'switch'"
          :model-value="computedValue[field.key]"
          @update:model-value="updateField(field.key, $event)"
          :label="field.label"
          :disabled="loading || field.disabled"
          :hint="field.hint"
          color="primary"
        />
      </VCol>
    </VRow>

    <!-- 表单按钮插槽 -->
    <slot name="actions" :valid="isValid" :submit="handleSubmit" :reset="resetForm">
      <VRow class="mt-4">
        <VCol cols="12" class="d-flex justify-end gap-3">
          <VBtn
            type="button"
            variant="outlined"
            @click="resetForm"
            :disabled="loading"
          >
            重置
          </VBtn>
          <VBtn
            type="submit"
            color="primary"
            :loading="loading"
            :disabled="!isValid"
          >
            提交
          </VBtn>
        </VCol>
      </VRow>
    </slot>
  </VForm>
</template>

<style scoped>
.field-label {
  font-weight: 500;
  color: #374151;
}

.gap-3 {
  gap: 12px;
}
</style>
